﻿using System;
using System.Collections.Generic;
using System.Text;

namespace IniFileManager
{
	/// <summary>
	/// Class represents element which contain reference to value
	/// </summary>
	sealed public class IniReferenceElement : IniElement
	{
		private string referenceSectionName;
		private string referencePropertyName;
		private IniData referenceData;

		/// <summary>
		/// Contructor of IniReferenceElement class.
		/// </summary>
		/// <param name="referenceData">Referenced data.</param>
		/// <param name="referenceSectionName">Referenced section name.</param>
		/// <param name="referencePropertyName">Referenced property name.</param>
		public IniReferenceElement( IniData referenceData, string referenceSectionName, string referencePropertyName )
		{
			this.referenceData = referenceData;
			this.referenceSectionName = referenceSectionName;
			this.referencePropertyName = referencePropertyName;
		}

		/// <summary>
		/// Method which is used to writing self to ini file. 
		/// </summary>
		/// <returns>String which will be written to ini file.</returns>
		public override string WriteSelf()
		{
			StringBuilder result = new StringBuilder();

			result.Append( TextConstants.referenceElementStartChar );
			result.Append( TextConstants.referenceElementLeftBracket );
			result.Append( this.referenceSectionName );
			result.Append( TextConstants.referenceElementDelimiterChar );
			result.Append( this.referencePropertyName );
			result.Append( TextConstants.referenceElementRightBracket );

			return result.ToString();
		}


		private object GetRecursivelyValue( List<IniElement> passedElements )
		{
			// TODO Petr: all
			if( passedElements.Contains( this ) )
			{
				throw new FormatException( "References elements have cyclic dependency." );
			}
			passedElements.Add( this );
			StringBuilder result = new StringBuilder();
			foreach( IniElement item in this.referenceData.Sections[referenceSectionName].Properties[referencePropertyName].Elements )
			{
				if( item.GetType() == typeof( IniReferenceElement ) )
				{
					result.Append( ( (IniReferenceElement)item ).GetRecursivelyValue( passedElements ).ToString() + " " );
				}
				else
				{
					result.Append( item.Value.ToString() + " " );
				}
			}

			passedElements.Remove( this );
			return result.ToString();
		}

		/// <summary>
		/// Gets or sets value stored in element.
		/// </summary>
		public override object Value
		{
			// TODO Petr: all
			get
			{
				return GetRecursivelyValue( new List<IniElement>() );
			}
			set
			{
				throw new ArgumentException( "Reference can not be changed." );
			}
		}
	}
}
